package server

import (
	"fmt"
	"math"
	"net/http"
	"strconv"
	"time"

	_ "embed"

	"github.com/julienschmidt/httprouter"
	"github.com/xmdhs/genshin-card/api"
	"github.com/xmdhs/genshin-card/template"
)

//go:embed index.html
var index []byte

func Server(addr string, cookie map[string][]string) error {
	mux := httprouter.New()
	mux.GET("/card/:region/:server/:skin/:uid", less(cookie))
	mux.GET("/detail/:region/:server/:skin/:uid", more(cookie))
	mux.GET("/svg/:skin/:gameID", more(cookie))
	mux.GET("/", func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
		w.Write(index)
	})

	s := http.Server{
		Addr:              addr,
		ReadHeaderTimeout: 4 * time.Second,
		WriteTimeout:      15 * time.Second,
		ReadTimeout:       7 * time.Second,
		Handler:           mux,
	}
	err := s.ListenAndServe()
	if err != nil {
		return fmt.Errorf("Server: %w", err)
	}
	return nil
}

func less(cookie map[string][]string) httprouter.Handle {
	return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
		card, _, shouldReturn := getData(p, w, cookie, true)
		if shouldReturn {
			return
		}

		server := p.ByName("server")
		acard := findCardInfo(server, card)

		t := card2temp(&acard, p.ByName("skin"))

		w.Header().Set("Content-Type", "image/svg+xml")
		w.Header().Set("Cache-Control", "max-age=600")
		t.Parse(w)
	}
}

func more(cookie map[string][]string) httprouter.Handle {
	return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
		var gameUid int
		var c *api.ApiConfig
		var server string

		if gameUids := p.ByName("gameID"); gameUids != "" {
			var r string
			server, r = api.GetServer(gameUids)
			config, ok := api.MihoyoAPI[r]
			if !ok {
				httpErrf(w, "region not found", 2, http.StatusBadRequest)
				return
			}
			c = &config
			c.UseCache = true
			apiConfigsetCookie(c, cookie, r)
			var err error
			gameUid, err = strconv.Atoi(gameUids)
			if err != nil {
				httpErrf(w, "gameID is not number", 5, http.StatusBadRequest)
				return
			}
		} else {
			var card *api.Card
			var shouldReturn bool
			card, c, shouldReturn = getData(p, w, cookie, true)
			if shouldReturn {
				return
			}
			server = p.ByName("server")
			acard := findCardInfo(server, card)
			var err error
			gameUid, err = strconv.Atoi(acard.GameRoleID)
			if err != nil {
				httpErrf(w, "invalid uid", 1, http.StatusBadRequest)
				return
			}
		}

		d, err := c.GetRoleIndex(gameUid, server, 32*time.Hour)
		if err != nil {
			httpErrf(w, err.Error(), -1, 500)
			return
		}

		role, ok := d.Data.Role.(map[string]interface{})
		if !ok {
			httpErrf(w, "invalid role", 4, http.StatusBadRequest)
			return
		}

		t := template.Card{
			More:        true,
			SkinBase64:  getSkin(p.ByName("skin")),
			Name:        getForMap[string](role, "nickname"),
			Level:       int(getForMap[float64](role, "level")),
			UID:         gameUid,
			C1:          int(getForMap[float64](d.Data.Stats, "luxurious_chest_number")),
			C2:          int(getForMap[float64](d.Data.Stats, "precious_chest_number")),
			C3:          int(getForMap[float64](d.Data.Stats, "exquisite_chest_number")),
			C4:          int(getForMap[float64](d.Data.Stats, "common_chest_number")),
			ActiveDays:  int(getForMap[float64](d.Data.Stats, "active_day_number")),
			Avatar:      int(getForMap[float64](d.Data.Stats, "avatar_number")),
			Achievement: int(getForMap[float64](d.Data.Stats, "achievement_number")),
			Wpiral:      getForMap[string](d.Data.Stats, "spiral_abyss"),
		}
		all := 0
		for _, v := range d.Data.WorldExplorations {
			all += v.ExplorationPercentage
		}
		fall := float64(all) / float64(len(d.Data.WorldExplorations))
		fall = math.Trunc(fall+0.5) / 10
		t.World = fmt.Sprintf("%v%%", fall)

		a, err := c.GetSpiralAbyss(gameUid, server, 32*time.Hour)
		if err != nil {
			httpErrf(w, err.Error(), -1, 500)
			return
		}
		t.AbyssStars = getAbyssStars(a)

		w.Header().Set("Content-Type", "image/svg+xml")
		w.Header().Set("Cache-Control", "max-age=1200")
		t.Parse(w)
	}
}
